#include "sparse_matrix.h"

sparse_matrix_lst* allocate_sparse_matrix_lst(int n)
{
	sparse_matrix_lst* sparse_matrix = 
		(sparse_matrix_lst*)malloc(sizeof(sparse_matrix_lst));
	if (sparse_matrix == NULL)
		goto allocate_sparse_matrix_lst_cleanup;

	sparse_matrix->cols = (cell_t**)calloc(n, sizeof(cell_t));
	if (sparse_matrix->cols == NULL)
		goto allocate_sparse_matrix_lst_cleanup;

	sparse_matrix->rows = (cell_t**)calloc(n, sizeof(cell_t));
	if (sparse_matrix->rows == NULL)
		goto allocate_sparse_matrix_lst_cleanup;

	sparse_matrix->n = n;
	return sparse_matrix;

allocate_sparse_matrix_lst_cleanup:
	if (sparse_matrix != NULL)
	{
		free(sparse_matrix);
	}
	if (sparse_matrix->cols != NULL)
	{
		free(sparse_matrix->cols);
	}
	if (sparse_matrix->rows != NULL)
	{
		free(sparse_matrix->rows);
	}
	return NULL;
}

void free_row(cell_t* cell)
{
	cell_t *curr_cell = NULL;

	while (cell != NULL)
	{
		curr_cell = cell;
		cell = cell->col_next;
		free(curr_cell);
	}
}

void free_sparse_matrix_lst(sparse_matrix_lst* matrix)
{
	int i = 0;
	int rows_no = matrix->n;
	
	/* Going over the rows releasing allocated info */
	for (i = rows_no - 1; i >= 0; --i)
	{
		if (matrix->rows[i] != NULL)
		{
			free_row(matrix->rows[i]);
		}
	}

	free(matrix->cols);
	free(matrix->rows);
	free(matrix);
}

void  mult_sparse_list(const sparse_matrix_lst* A, const elem* v, elem* result)
{
	if (A != NULL && A->rows != NULL)
	{
		int size = A->n;
		elem sum = 0;
		int i = 0;
		cell_t* current_cell = NULL;

		for(i = 0; i < size; i++)
		{
			sum = 0;
			current_cell = A->rows[i];
			while(current_cell != NULL)
			{
				sum += current_cell->value * v[current_cell->colind];
				current_cell = current_cell->col_next;
			}
			result[i] = sum;
		}
	}
}
